package cn.cloudtogo.server.redis;

import cn.cloudtogo.common.GendbException;
import cn.cloudtogo.common.model.DatasourceTypes;
import cn.cloudtogo.common.model.ExternalDatasourceDao;
import cn.cloudtogo.common.model.ExternalDatasourceModel;
import cn.cloudtogo.common.types.ObjectId;
import cn.cloudtogo.common.types.RequestHeaderObject;
import cn.cloudtogo.common.util.RedisConnectionInfo;
import cn.cloudtogo.common.util.StringHelper;
import cn.cloudtogo.support.redis.RedisConnectionHelper;
import cn.cloudtogo.support.redis.RedisExternalDatasourceCreateParam;
import cn.cloudtogo.support.redis.RedisExternalDatasourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

import static cn.cloudtogo.common.util.RedisUrlHelper.parseUrl;

/**
 * @author yaolianhua789@gmail.com
 **/
@Service
@Slf4j
public class RedisExternalDatasourceServiceImpl implements RedisExternalDatasourceService {

    private final ExternalDatasourceDao externalDatasourceDao;
    private final SpringRedisTemplateContext context;

    public RedisExternalDatasourceServiceImpl(ExternalDatasourceDao externalDatasourceDao, SpringRedisTemplateContext context) {
        this.externalDatasourceDao = externalDatasourceDao;
        this.context = context;
    }

    private synchronized String obtainProject(RedisExternalDatasourceCreateParam param) {
        String project = param.getProject();
        if (StringUtils.hasText(project)) {
            return project;
        }
        String openid = param.getOpenid();
        String name = param.getName();
        String url = param.getUrl();
        int database = param.getSchema();

        long currentTimeMillis = System.currentTimeMillis();
        project = StringHelper.encode("|", new String[]{url, String.valueOf(database), openid, name, String.valueOf(currentTimeMillis)});

        return project;
    }

    @Override
    public String create(RedisExternalDatasourceCreateParam param) {

        String url = param.getUrl();
        RedisConnectionInfo redisConnectionInfo = parseUrl(url);

        //check connection
        RedisConnectionHelper.ConnectionValidBind connectionValidBind = RedisConnectionHelper.isValidConnection(param.getUrl());
        if (!connectionValidBind.isValid()) {
            throw new GendbException(String.format("redis connection failure [%s]", redisConnectionInfo.getUrl()));
        }

        String uuid = ObjectId.get().toHexString();

        //save external datasource
        ExternalDatasourceModel externalDatasourceModel = new ExternalDatasourceModel();
        externalDatasourceModel.setUuid(uuid);
        externalDatasourceModel.setOpenid(param.getOpenid());
        externalDatasourceModel.setProject(obtainProject(param));
        externalDatasourceModel.setName(param.getName());
        externalDatasourceModel.setUrl(url);
        externalDatasourceModel.setSchema(String.valueOf(param.getSchema()));
        externalDatasourceModel.setUsername(redisConnectionInfo.getUsername());
        externalDatasourceModel.setPassword(redisConnectionInfo.getPassword());
        externalDatasourceModel.setType(DatasourceTypes.Redis);
        externalDatasourceModel.setHost(redisConnectionInfo.getHost());
        externalDatasourceModel.setPort(redisConnectionInfo.getPort());
        externalDatasourceModel.setCreateAt(LocalDateTime.now());

        externalDatasourceDao.save(externalDatasourceModel);

        // refresh redis template context
        RequestHeaderObject headerObject = RequestHeaderObject.ofModel(externalDatasourceModel);
        RedisTemplate<String, Object> redisTemplate = RedisConnectionHelper.getRedisTemplate(connectionValidBind.getRedisConnectionFactory());

        context.putRedisTemplate(headerObject, redisTemplate);

        return uuid;

    }

}
